#!/usr/bin/env ruby
# - pr_url

require 'json'
require 'openssl'
require 'base64'
require 'rest-client'
require "#{ENV['LKP_SRC']}/lib/log.rb"
require "#{ENV['LKP_SRC']}/lib/write_json.rb"

BASE_URL = "https://sca.osinfra.cn/gateway/dm-service/scan"

class MajunScanSca
  def initialize
    @resource = RestClient::Resource.new(BASE_URL)
    @pr_url = ENV["pr_url"]
    @private_token = ENV["secrets_private_token"]
    @app_id = ENV["secrets_app_id"]
    @secret_key = ENV["secrets_secret_key"]
  end

  def ak_sk_signature(timestamp)
    message = "#{@app_id}#{timestamp.to_s}"
    sha256 = OpenSSL::Digest.new('sha256')
    sign = OpenSSL::HMAC.digest(sha256, @secret_key, message)
    Base64.strict_encode64(sign)
  end

  def wait_scan_sca_finish(params)
    while true
      timestamp = (Time.now.to_f * 1000).to_i
      begin
        response = @resource["result"].get(
          :params => params, 
          :content_type => 'application/json',
          :appId => @app_id,
          :timestamp => timestamp,
          :sign => ak_sk_signature(timestamp)
        )
      rescue Exception => e
        log_warn "Failed to query scan sca result from Majun: #{e.message}"
        raise e
      end
      
      body = JSON.parse(response.body)
      log_info response.body
      
      begin
        code = body["code"]
        message = body["message"]
        data = body.fetch("data", {})
        total = body["total"]
      rescue Exception => e
        log_error "Failed to parse response body: #{e.message}"
        
        log_info "Waiting 30 seconds for next query..."
        sleep 30
        next
      end
      
      if code == 200
        pr_url = data["prUrl"]
        unconfirmed_file_num = data["unconfirmedFileNum"]
        state = data["state"]
        
        if state == "success" && !unconfirmed_file_num.nil? && unconfirmed_file_num >= 0
          write_json data, "majun-scan-sca-result"
          log_info "#{state}: #{body}"
          break

        elsif state == "failure" && !unconfirmed_file_num.nil? && unconfirmed_file_num == -1
          write_json data, "majun-scan-sca-result"
          raise "#{state}: #{body}"
        
        elsif state == "scanning"
          log_info state
        
        else
          raise "Unknown state: #{state}"
        end
      
      elsif code == 403
        log_error "Fail to access api authorization: #{code}"

      elsif code == 500
        log_error "Interval server error: #{code}"

      else
        log_warn "Unknown code of response: #{code}"
      end

      log_info "Waiting 30 seconds for next query..."
      sleep 30
    end
  end

  def run
    data = {
      :prUrl => @pr_url,
    }

    timestamp = (Time.now.to_f * 1000).to_i
    begin
      response = @resource['pr'].post(
        data.to_json, 
        :content_type => 'application/json',
        :appId => @app_id,
        :timestamp => timestamp,
        :sign => ak_sk_signature(timestamp)
      )
    rescue Exception => e
      log_error "Failed to create scan sca task from Majun: #{data.to_json} => #{response}"
      raise e
    end
      
    raise "Failed to create scan sca task from Majun: #{response}" unless response.code == 200

    body = JSON.parse(response.body)
    pp body
    begin
      scan_id = body["data"]
    rescue
      raise "Failed to create scan sca task from Majun: #{response}"
    end

    query_data = {
      :scanId => scan_id,
    }

    wait_scan_sca_finish query_data
  end
end

system('ntpdate cn.pool.ntp.org')
MajunScanSca.new.run
